 /*
  * Copyright 2016-2021 the original author or authors from the JHipster project.
  *
  * This file is part of the JHipster project, see https://www.jhipster.tech/
  * for more information.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package com.alibaba.otter.manager.web.utils;

 import com.alibaba.otter.manager.web.dto.RestResponse;
 import com.google.common.base.CaseFormat;
 import com.mybatisflex.core.paginate.Page;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.data.domain.Pageable;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.ResponseEntity;
 import org.springframework.util.Assert;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 import org.springframework.web.util.UriComponentsBuilder;

 import java.text.MessageFormat;
 import java.util.List;

 /**
  * Utility class for handling pagination.
  *
  * <p>
  * Pagination uses the same principles as the <a href="https://developer.github.com/v3/#pagination">GitHub API</a>,
  * and follow <a href="http://tools.ietf.org/html/rfc5988">RFC 5988 (Link header)</a>.
  */
 public enum PaginationUtil {

     ;
     private static final String HEADER_X_TOTAL_COUNT = "X-Total-Count";

     private static final String HEADER_X_NEXT = "X-Page-Next";

     private static final String HEADER_X_SKIP = "X-Page-Skip";

     private static final String HEADER_LINK_FORMAT = "<{0}>; rel=\"{1}\"";

     /**
      * 分页适配
      */
     public static <T> Page<T> of(Pageable pageable) {

         // 排序
         // 构建分页请求
         return Page.of(pageable.getPageNumber(), pageable.getPageSize());
     }

     public static String toUnderLine(String u){
         return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, u);
     }



     public static <T> Page<T> of(List<T> content, Page<?> pageable) {
         Page<T> tPage = Page.of(pageable.getPageNumber(), pageable.getPageSize());
         tPage.setRecords(content);
         return tPage;
     }

     /**
      * Generate pagination headers for a Spring Data {@link org.springframework.data.domain.Page} object.
      *
      * @param uriBuilder The URI builder.
      * @param page       The page.
      * @param <T>        The type of object.
      * @return http header.
      */
     public static <T> void generatePaginationHttpHeaders(HttpServletResponse response, UriComponentsBuilder uriBuilder, Page<T> page) {
         response.addHeader(HEADER_X_TOTAL_COUNT, Long.toString(page.getTotalRow()));
         String link = getLinkString(uriBuilder, page);
         response.addHeader(HttpHeaders.LINK, link);
     }


     public static <T> ResponseEntity<RestResponse<List<T>>> pageResponse(Page<T> page) {
         return pageResponse(ServletUriComponentsBuilder.fromCurrentRequest(), page);
     }

     /**
      * 加载下一页分页信息
      *
      * @param date
      * @param skip
      * @param hasNext
      * @param <T>
      * @return
      */
     public static <T> ResponseEntity<RestResponse<List<T>>> pageResponse(List<T> date, Integer skip, Boolean hasNext) {
         HttpHeaders httpHeaders = new HttpHeaders();
         httpHeaders.add(HEADER_X_SKIP, Integer.toString(skip));
         httpHeaders.add(HEADER_X_NEXT, Boolean.toString(hasNext));
         return ResponseEntity.ok().headers(httpHeaders).body(RestResponse.ok(date));
     }

     /**
      * Generate pagination headers for a Spring Data {@link org.springframework.data.domain.Page} object.
      *
      * @param uriBuilder The URI builder.
      * @param page       The page.
      * @param <T>        The type of object.
      * @return http header.
      */
     public static <T> ResponseEntity<RestResponse<List<T>>> pageResponse(UriComponentsBuilder uriBuilder, Page<T> page) {
         HttpHeaders httpHeaders = new HttpHeaders();
         httpHeaders.add(HEADER_X_TOTAL_COUNT, Long.toString(page.getTotalRow()));
         String link = getLinkString(uriBuilder, page);
         httpHeaders.add(HttpHeaders.LINK, link);
         return ResponseEntity.ok().headers(httpHeaders).body(RestResponse.ok(page.getRecords()));
     }

     public static <T> RestResponse<List<T>> unPage(Pageable pageable){
         Page<T> page = Page.of(pageable.getPageNumber(), pageable.getPageSize(), 0L);
         return pageHttpResponse(page);
     }

     public static <T> RestResponse<List<T>> page(Pageable pageable,long total,List<T> data){
         Page<T> page = Page.of(pageable.getPageNumber(), pageable.getPageSize(), total);
         page.setRecords(data);
         return pageHttpResponse(page);
     }

     /**
      * Generate pagination headers for a Spring Data {@link org.springframework.data.domain.Page} object.
      *
      * @param page The page.
      * @param <T>  The type of object.
      * @return http header.
      */
     public static <T> RestResponse<List<T>> pageHttpResponse(Page<T> page) {

         ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
         HttpServletResponse response = requestAttributes.getResponse();
         Assert.notNull(response, "No current HttpServletResponse");
         // set header
         response.setHeader(HEADER_X_TOTAL_COUNT, Long.toString(page.getTotalRow()));
         String link = getLinkString(ServletUriComponentsBuilder.fromCurrentRequest(), page);
         response.setHeader(HttpHeaders.LINK, link);

         return RestResponse.ok(page.getRecords());
     }

     private static <T> String getLinkString(UriComponentsBuilder uriBuilder, Page<T> page) {
         long pageNumber = page.getPageNumber();
         long pageSize = page.getPageSize();
         StringBuilder link = new StringBuilder();
         if (pageNumber < page.getTotalPage() - 1) {
             link.append(prepareLink(uriBuilder, pageNumber + 1, pageSize, "next"))
                     .append(",");
         }
         if (pageNumber > 0) {
             link.append(prepareLink(uriBuilder, pageNumber - 1, pageSize, "prev"))
                     .append(",");
         }
         link.append(prepareLink(uriBuilder, page.getTotalPage() - 1, pageSize, "last"))
                 .append(",")
                 .append(prepareLink(uriBuilder, 0, pageSize, "first"));
         return link.toString();
     }

     private static String prepareLink(UriComponentsBuilder uriBuilder, long pageNumber, long pageSize, String relType) {
         return MessageFormat.format(HEADER_LINK_FORMAT, preparePageUri(uriBuilder, pageNumber, pageSize), relType);
     }

     private static String preparePageUri(UriComponentsBuilder uriBuilder, long pageNumber, long pageSize) {
         return uriBuilder.replaceQueryParam("page", Long.toString(pageNumber))
                 .replaceQueryParam("size", Long.toString(pageSize))
                 .toUriString()
                 .replace(",", "%2C")
                 .replace(";", "%3B");
     }
 }
